/*!
\file L298Driver.h

\author Mauricio Martins da Costa
\date
*/
#ifndef __L298Driver_H__
#define __L298Driver_H__

#include <Arduino.h>
/*! Main class to interface L298 IC's. 
<p><i>
The L298 is an integrated monolithic circuit in a 15-lead Multiwatt and PowerSO20 packages. 
It is a high voltage, high current dual full-bridge driver designed to accept standard TTL logic 
levels and drive inductive loads such as relays, solenoids, DC and stepping motors. 
Two enable inputs are provided to enable or disable the device independently of the input signals. 
The emitters of the lower transistors of each bridge are connected together and the corresponding 
external terminal can be used for the connection of an external sensing resistor. 
An additional supply input is provided so that the logic works at a lower voltage.
</i></p>
<p>
For more information on this IC check manufacturer's datasheet: http://www.st.com/web/catalog/sense_power/FM142/CL851/SC1790/SS1555/PF63147
</p>
*/
class L298Driver {
  private:
    // define pins relevant to the control of L298
    uint8_t _pinA,_pinB,_pinC,_pinD, _pinEN1, _pinEN2, _pinSENS1, _pinSENS2;
   
  public:
  
/*! Constructor.
<p>
Core constructor not requiring any reference to SENS pins. 
<i>Use this constructor only if these pins aren't used!</i>
</p>
	\param pinA the number of pin in Arduino that will map to A input 
	\param pinB the number of pin in Arduino that will map to B input 
	\param pinC the number of pin in Arduino that will map to C input 
	\param pinD the number of pin in Arduino that will map to D input 
	\param pinEN1 the number of pin in Arduino that will map to EN1 input 
	\param pinEN2 the number of pin in Arduino that will map to EN2 input 
	<br>
	Usage:
	\code
		// instantiate motor using Arduino pins 5..10
		// 6 and 9 are PWM pins, so we'll be using to control
		// motor speed
		L298Driver motor=L298Driver(5,7,8,10,6,9)
	\endcode
*/
  L298Driver(uint8_t pinA,uint8_t pinB,uint8_t pinC,uint8_t pinD,uint8_t pinEN1,uint8_t pinEN2);
/*! Constructor.
<p>
Core constructor requiring reference to SENS pins. 
<i>Use this constructor only if these pins will be used!</i>
<em>SENS pins must be tied to Analogic pins!</em>
</p>
	\param pinA the number of pin in Arduino that will map to A input 
	\param pinB the number of pin in Arduino that will map to B input 
	\param pinC the number of pin in Arduino that will map to C input 
	\param pinD the number of pin in Arduino that will map to D input 
	\param pinEN1 the number of pin in Arduino that will map to EN1 input 
	\param pinEN2 the number of pin in Arduino that will map to EN2 input 
	\param pinSENS1 the number of pin in Arduino that will map to SENS1 output 
	\param pinSENS2 the number of pin in Arduino that will map to SENS2 output 
	<br>
	Usage:
	\code
		// instantiate motor using Arduino pins 5..10
		// 6 and 9 are PWM pins, so we'll be using to control
		// motor speed, 14 and 15 are A0 and A1 respectively
		// so we'll use to monitor current levels
		L298Driver motor=L298Driver(5,7,8,10,6,9,14,15)
	\endcode
*/
  L298Driver(uint8_t pinA,uint8_t pinB,uint8_t pinC,uint8_t pinD,uint8_t pinEN1,uint8_t pinEN2,uint8_t pinSENS1, uint8_t pinSENS2);

/*! Activate an specific channel.
<p>This instruction works only in EN lines. If a EN line is brought 1 (up), it turns outputs active depending on AB (or CD depending the channel) lines status.</p>
<p>On() uses digitalWrite to control EN lines</p>
\param channel indicates the channel this instruction will actuate (L298_A_CHANNEL or L298_B_CHANNEL or both);
<br> Usage
\code
	motor.On(L298_A_CHANNEL); // activate only channel A
	...
	motor.On(L298_A_CHANNEL|L298_B_CHANNEL); // activate both channels
\endcode
*/
void On(uint8_t channel);

/*! Deactivate an specific channel.
<p>This instruction works only in EN lines. If a EN line is brought 0 (down), it turns outputs 0 too (AB (or CD depending the channel) lines status will be ignored)</p>
<p>Off() uses digitalWrite to control EN lines</p>
\param channel indicates the channel this instruction will actuate (L298_A_CHANNEL or L298_B_CHANNEL or both);
<br> Usage
\code
	motor.Off(L298_A_CHANNEL); // activate only channel A
	...
	motor.Off(L298_A_CHANNEL|L298_B_CHANNEL); // activate both channels
\endcode
*/
void Off(uint8_t channel);

/*! Activate an specific channel at specified speed.
<p>This instruction works only in EN lines tied to PWM. It turns the specified channel active with a PWM signal.</p>
<p>Run() uses analogWrite() to control EN lines</p>
\param channel indicates the channel this instruction will actuate (L298_A_CHANNEL or L298_B_CHANNEL or both)
\param speed sets the PWM duty cycle. 0(0%)...255(100%);
<br>Usage
\code
	motor.Run(L298_A_CHANNEL, 128); // run motor in channel A with half speed
\endcode
*/
  void Run(uint8_t channel, uint8_t speed);

/*! Stop an specific channel.
<p>This instruction works only in EN lines tied to PWM. It sets to 0 (zero) the duty cycle for the specified channel</p>
\param channel indicates the channel this instruction will actuate (L298_A_CHANNEL or L298_B_CHANNEL or both)
<br>Usage
\code
	motor.Stop(L298_A_CHANNEL); // stop motor at A channel 
\endcode
*/
  void Stop(uint8_t channel);

/*! Set output configuration.
<p>This instruction works only in AB/CD lines only. It sets the state of the pins - consequently the output activation</p>
\param channel indicates the channel this instruction will actuate (L298_A_CHANNEL or L298_B_CHANNEL or both)
\param state the state of the output (L298_BRAKE1, L298_CW, L298_CCW, L298_BRAKE2)
<br>
Usage
\code
	motor.Set(L298_A_CHANNEL, L298_CW); // spindles motor A in CW direction
	motor.Set(L298_B_CHANNEL, L298_CCW); // spindles motor B in CCW direction
\endcode
*/
  void Set(uint8_t channel, uint8_t state);

/*! Read Voltage over RSENS in specific channel.
<p>This instruction works on SENS pins. It reads the voltage across the RSENS resistors for the specified channel.</p>
<p>The output is a value proportional to the current passing across RSENS, properly quantified in 10bits (resolution of Arduino Analog channels);
\param channel indicates the channel this instruction will actuate (L298_A_CHANNEL or L298_B_CHANNEL)
\return value is the voltage read in RSENS' channel.
*/
  uint16_t ReadVSens(uint8_t channel);  
};


//! L298_A_CHANNEL constant relates to L298 A channel
#define L298_A_CHANNEL 0x01
//! L298_B_CHANNEL constant relates to L298 B channel
#define L298_B_CHANNEL 0x02

//! L298_BRAKE1 sets output "0"-"0"
#define L298_BRAKE1 0x00
//! L298_CW sets output "0"-"1"
#define L298_CW 0x01
//! L298_CCW sets output "1"-"0"
#define L298_CCW 0x02
//! L298_BRAKE2 sets output "1"-"1"
#define L298_BRAKE2  0x03

#endif
